#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2025 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import json
import sys
from typing import List, Dict
import os
import logging


class FileEntity:
    def __init__(self, file_name: str, file_path: str, base_path: str):
        self.file_name = file_name
        self.file_path = file_path
        self.full_path = os.path.join(base_path, file_path)

    def __repr__(self):
        return (f"FileEntity(file_name={self.file_name}, "
                f"full_path={self.full_path}, file_path={self.file_path})")


class ErrorInfoBuilder:
    def __init__(self):
        self.error_info = {
            "analyzerName": "xtscheck",
            "codeContextStartLine": 0,
            "defectLevel": "0",
            "language": "arkts"
        }

    def set_buggy_file_path(self, buggy_file_path):
        self.error_info["buggyFilePath"] = buggy_file_path
        return self

    def set_defect_type(self, defect_type):
        self.error_info["defectType"] = defect_type
        return self

    def set_description(self, description):
        self.error_info["description"] = description
        return self

    def set_main_buggy_line(self, main_buggy_line):
        self.error_info["mainBuggyLine"] = str(main_buggy_line)
        return self

    def set_main_buggy_code(self, main_buggy_code):
        self.error_info["mainBuggyCode"] = main_buggy_code
        return self

    def set_language(self, language):
        self.error_info["language"] = language
        return self

    def build(self):
        return self.error_info


class FileDataSingleton:
    _instance = None
    _data: List[FileEntity] = []
    project_dir: str = ""
    rules: List[str] = []
    output_path: str = ""
    params_file_path: str = ""

    debug_mode: bool = False

    debug_defaults = {
        "log_dir": "./log",
        "rules": [
            "XTS.CHECK.TESTJSON.01",
            "XTS.CHECK.TESTCASE.01",
            "XTS.CHECK.TESTSUITE.01",
            "XTS.CHECK.SETENFORCE.01",
            "XTS.CHECK.SIGNATURE.01",
            "XTS.CHECK.HAPNAME.01",
            "XTS.CHECK.APPFREEEZE.01",
            "XTS.CHECK.TESTFILENAME.01",
            "XTS.CHECK.TCNUMBER.01",
            "XTS.CHECK.TCNAME.01",
            "XTS.CHECK.TCDESC.01",
            "XTS.CHECK.TCLEVEL.01",
            "XTS.CHECK.TCSIZE.01",
            "XTS.CHECK.TCTYPE.01",
            "XTS.CHECK.HVIGOR.01",
            "XTS.CHECK.ASSERTION.01",
            "XTS.CHECK.SYSCAP.01",
            "XTS.CHECK.PARTNAME.01",
            "XTS.CHECK.ABILITYMS.01",
            "XTS.CHECK.LEVEL.01"
        ],
        "output_path": "./res/xts_result.json",
        "params_file_path": "./list.json",
        "project_dir": "./case/code/"
    }

    def __new__(cls, *args, **kwargs):

        logger = logging.getLogger('my_logger')
        if not cls._instance:
            if cls.debug_mode:
                cls.log_dir = cls.debug_defaults["log_dir"]
                cls.rules = cls.debug_defaults["rules"]
                cls.output_path = cls.debug_defaults["output_path"]
                cls.params_file_path = cls.debug_defaults["params_file_path"]
                cls.project_dir = cls.debug_defaults["project_dir"]
            else:
                if len(sys.argv) > 1:
                    if len(sys.argv) == 6:
                        cls.log_dir = sys.argv[1]
                        cls.rules = sys.argv[2].split('@')
                        cls.output_path = sys.argv[3]
                        cls.params_file_path = sys.argv[4]
                        cls.project_dir = sys.argv[5]
                    else:
                        logger.error(
                            "错误：提供的参数数量不正确。请使用以下格式：python script.py log_dir rules output_path params_file_path "
                            "project_dir")
                        sys.exit(1)
                else:
                    logger.error(
                        "错误：未提供任何参数。请使用以下格式：python script.py log_dir rules output_path params_file_path project_dir")
                    sys.exit(1)

            cls._instance = super(FileDataSingleton, cls).__new__(cls)
            cls._instance._load_data()
            cls._instance._configure_logging()

        return cls._instance

    def _configure_logging(self):
        logger = logging.getLogger('my_logger')
        logger.setLevel(logging.DEBUG)
        console_handler = logging.StreamHandler()
        complete_log = self.log_dir + "/xtscheck_log.log"
        file_handler = logging.FileHandler(complete_log, "w")
        formatter = logging.Formatter('[%(levelname)s] %(asctime)s [%(filename)s] - %(message)s')
        console_handler.setFormatter(formatter)
        file_handler.setFormatter(formatter)
        logger.addHandler(console_handler)
        logger.addHandler(file_handler)

    def _load_data(self):
        logger = logging.getLogger('my_logger')
        try:
            with open(self.params_file_path, 'r') as file:
                json_data = json.load(file)
                for item in json_data:
                    file_entity = FileEntity(item['file_name'], item['file_path'], self.project_dir)
                    self._data.append(file_entity)
        except FileNotFoundError:
            logger.error(f"JSON file not found at {self.params_file_path}.")
            sys.exit(1)
        except json.JSONDecodeError:
            logger.error("Error decoding JSON file.")
            sys.exit(1)

    def get_file(self) -> List[FileEntity]:
        return self._data

    def write_error_to_json_file(self, error_info: Dict):
        output_file = os.path.join(self.output_path)
        try:
            if os.path.exists(output_file):
                with open(output_file, 'r', encoding='utf-8') as f:
                    existing_errors = json.load(f)
            else:
                existing_errors = []

            existing_errors.append(error_info)

            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(existing_errors, f, ensure_ascii=False, indent=4)
        except Exception as e:
            logger = logging.getLogger('my_logger')
            logger.error(f"Failed to write error to JSON file: {e}")
            sys.exit(1)


FileDataSingleton.debug_mode = False
utils_data = FileDataSingleton()
